﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TurtleLib.ComputerCraft;
using TurtleLib.Simulation;

namespace TurtleTest
{
  class Program
  {
    private static void Expand(World world, IPeripheral per)
    {
      var panel = world.GetUx(per);
  
      if (panel != null)
        panel.Expanded = true;
    }

    [STAThread]
    static void Main(string[] args)
    {
      var world = new World();

      // simulate a computer commanding a single turtle to move forward until it finds a block and break it

      var c1 = new Computer();
      var c2 = new AdvancedComputer();
      var t1 = new Turtle();
      var c3 = new AdvancedComputer();
      var c4 = new Computer();

      world.AddEntity(c1, new Point3D(0, 0, 0), initiallyExpanded: true);
      world.AddEntity(t1, new Point3D(10, 0, 0), initiallyExpanded: true);

      world.AddEntity(c2, new Point3D(20, 0, 0), initiallyExpanded: true);
      world.AddEntity(c3, new Point3D(21, 0, 0), initiallyExpanded: true);

      var mloc = new Point3D(22, 0, 9);
      world.AddEntity(c4, mloc, Face.East, initiallyExpanded: true);

      world.AddEntity(new AdvancedMonitor(), mloc.Offset(0, 0, -1), Face.South, initiallyExpanded: true);
      world.AddEntity(new AdvancedMonitor(), mloc.Offset(1, 0, -1), Face.South);
      world.AddEntity(new AdvancedMonitor(), mloc.Offset(0, 1, -1), Face.South);
      world.AddEntity(new AdvancedMonitor(), mloc.Offset(1, 1, -1), Face.South);

      world.AddEntity(new Monitor(), mloc.Offset(0, 0, 1), Face.East, initiallyExpanded: true);
      world.AddEntity(new Monitor(), mloc.Offset(0, 0, 2), Face.East);
      world.AddEntity(new Monitor(), mloc.Offset(0, 1, 1), Face.East);
      world.AddEntity(new Monitor(), mloc.Offset(0, 1, 2), Face.East);

      var c5 = new Computer();
      world.AddEntity(c5, new Point3D(0, 0, 100), Face.South, initiallyExpanded: true);

      // install modems on both
      // because modems move with their objects, I just cheat and use a helper
      //world.AttachModem(computer, Side.Left);
      //world.AttachModem(turtle, Side.Left);

      // create world block for the turtle to find
      //var dirt = new Block(BlocKType.Dirt);
      //world.AddEntity(dirt, new Point(15, 0, 0));

      Action<Term, string> WriteLine = (term, text) =>
      {
        var size = term.getSize();
        int height = size.Item2 - 1;

        var curPos = term.getCursorPos();
        bool forceScroll = curPos.Item2 == (height + 1);

        term.write(text);

        term.setCursorPos(1, curPos.Item2 + 1);

        if (forceScroll)
        {
          term.scroll(1);
        }
      };

      world.SetBootComputerScript(c1, _ =>
      {
        Action<string> writeLine = text =>
        {
          WriteLine(_.term, text);
        };

        _.term.write("test");
        _.term.write("test");
        _.term.write("test");
        writeLine(string.Empty);
        writeLine("new line");
        writeLine("new line");
        writeLine("new line");
        _.os.sleep(1);
        _.term.clear();
        _.term.setCursorPos(1, 1);

        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("123456789A123456789B123456789C123456789D123456789E1");
        writeLine("abcdefghijklmnopqrstuvwxyz");
      });

      world.SetBootComputerScript(c2, _ =>
      {
        WriteLine(_.term, "first line");
        _.term.write("second line");
        _.os.sleep(1);

        _.term.clearLine();
        _.os.sleep(1);
        WriteLine(_.term, "rewritten second line");
        WriteLine(_.term, "is color: " + _.term.isColor().ToString());

        _.os.sleep(1);
        _.term.scroll(3);
        WriteLine(_.term, "scrolled");

        _.term.setBackgroundColor(colors.orange);
        _.term.write("only this should be orange");
        _.os.sleep(1);
        _.term.setBackgroundColor(colors.black);

        _.term.scroll(1);
        _.term.write("scrolled");
        _.term.scroll(1);
        _.term.write("scrolled");
        _.term.scroll(1);
        _.term.write("scrolled");
      });

      world.SetBootTurtleScript(t1, _ =>
      {
        _.term.setCursorPos(0, 1);

        _.term.write("i'm a turtle!");
      });

      world.SetBootComputerScript(c3, _ =>
      {
        _.term.setBackgroundColor(colors.red);
        _.term.write("          ");
        _.term.setBackgroundColor(colors.black);
        _.term.write("   ");
        _.term.setBackgroundColor(colors.blue);
        WriteLine(_.term, "b");
        WriteLine(_.term, "bb");
        WriteLine(_.term, "bbb");
        WriteLine(_.term, "bbbb");
        WriteLine(_.term, "bbbbb");

        string full = "123456789A123456789B123456789C123456789D123456789E1";
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        WriteLine(_.term, full);
        for (int i = 0; i < full.Length; i++)
        {
          int ci = 1 << (i % 16);
          colors c = (colors)ci;
          _.term.setBackgroundColor(c);
          _.term.write(full[i].ToString());
        }

        _.term.setBackgroundColor(colors.yellow);
        _.term.write("c");
        _.term.setBackgroundColor(colors.red);
        _.term.write("d");
      });

      world.SetBootComputerScript(c4, _ =>
      {
        // c4 is facing east
        // mon1 is to the z-pos which is north
        // north is right of east face
        var monitor = _.peripheral.wrap<Monitor>(Side.Right);

        WriteLine(monitor, "wrap");

        WriteLine(_.term, "local, next redirect");

        _.term.redirect(monitor);

        WriteLine(_.term, "redirected");

        _.term.restore();

        WriteLine(_.term, "and back");

        WriteLine(_.term, "this regular computer has color: " + _.term.isColor());

        monitor = _.peripheral.wrap<Monitor>(Side.Left);
        WriteLine(_.term, "wrap: " + (monitor == null ? "null" : monitor.GetType().Name));
        WriteLine(_.term, "wrap object has color: " + monitor.isColor());

        _.term.redirect(monitor);
        WriteLine(_.term, "c?" + _.term.isColor());
        _.term.setTextColor(colors.red);
        WriteLine(_.term, "red");
        _.term.restore();
        WriteLine(_.term, "and back");
      });

      world.SetBootComputerScript(c5, _ =>
      {
        WriteLine(_.term, "OS api tests");

        var size = _.term.getSize();
        int height = size.Item2 - 1;

        for (int i = 0; i < height * 2; i++)
        {
          WriteLine(_.term, "os clock: " + _.os.clock());
          System.Threading.Thread.Sleep(25);
        }

        WriteLine(_.term, "os clock test complete");
        _.os.sleep(1);
        _.term.clear();
        _.term.setCursorPos(1, 1);

        WriteLine(_.term, "id: " + _.os.getComputerID());
        WriteLine(_.term, "version: " + _.os.version());
        _.os.setComputerLabel("test label hello hello");
        WriteLine(_.term, "label: " + _.os.getComputerLabel());
      });

      world.Run();
    }
  }
}
